package dbb

import (
	"reflect"
	"strconv"
	"strings"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/data/binding"
	"fyne.io/fyne/v2/dialog"
	"fyne.io/fyne/v2/widget"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/text/gstr"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/gogf/gf/v2/util/gutil"
	"github.com/goki/ki/ki"
	"github.com/y2h/fyne_poem/util"
	"github.com/y2h/fyne_poem/widgets"
)

// ALTER TABLE table_name ADD column_name datatype
// ALTER TABLE table_name DROP COLUMN column_name
// ALTER TABLE table_name ALTER COLUMN column_name datatype
// ALTER TABLE database_name.table_name RENAME TO new_table_name;

func Field(db gdb.DB, tbl string,
	msg *widget.Label, w fyne.Window) fyne.CanvasObject {
	bdcols := binding.NewInt()
	// 当前表字段节点
	var nd ki.Ki
	setup()

	fds, cols := TableFields2(db, tbl)
	if len(cols) == 0 {
		return widget.NewLabel("no data")
	}
	// 表的列结构体类型
	// 表的列结构体字段数量
	fk := gutil.Keys(fds[cols[0]])
	numfd := len(fk)
	head := container.NewGridWithColumns(numfd)
	for i := 0; i < numfd; i++ {
		head.Add(widget.NewLabel(fk[i]))
	}
	lst := FieldList(numfd)
	right := widgets.Frmtblfield()
	lbl := widget.NewLabel("")
	colNamesel := ""
	selectedID := 0
	fsel := func(id widget.ListItemID) {
		selectedID = id
		colNamesel = cols[id]
		lbl.SetText(gconv.String(fds[cols[id]]))

		right.Items[0].Widget.(*widget.Entry).
			SetText(gconv.String(fds[cols[id]].Index))
		right.Items[1].Widget.(*widget.Entry).
			SetText(fds[cols[id]].Name)
		right.Items[2].Widget.(*widget.Select).
			SetSelected(gstr.ToUpper(fds[cols[id]].Type))
		right.Items[3].Widget.(*widget.Check).
			SetChecked(fds[cols[id]].Null)
		right.Items[4].Widget.(*widget.Entry).
			SetText(fds[cols[id]].Key)
		right.Items[5].Widget.(*widget.Entry).
			SetText(gconv.String(fds[cols[id]].Default))
		right.Items[6].Widget.(*widget.Entry).
			SetText(fds[cols[id]].Extra)
		right.Items[7].Widget.(*widget.Entry).
			SetText(fds[cols[id]].Comment)
		msg.SetText(colNamesel)
	}
	lst.OnSelected = func(id widget.ListItemID) { fsel(id) }
	// 数据表格容器
	ctnlst := container.NewMax(lst)
	bdcols.AddListener(binding.NewDataListener(func() {
		fds, cols = TableFields2(db, tbl)
		// 找到当前表节点，更新其子节点
		ktbls := "Tables(" + gconv.String(Me.Tbls.Len()) + ")"
		tblnode := parent.ChildByName(Me.Name, 0).
			ChildByName(ktbls, 0)
		nd = tblnode.ChildByName(tbl, 0).Child(0)
		nm := ("字段(" + gconv.String(len(cols)) + ")")
		nd.SetName(nm)
		RefreshDbtree()
		// 重置字段表格
		bdl.Set([]string{})
		for i := 0; i < len(cols); i++ {
			vas := gutil.Values(fds[cols[i]])
			bdl.Append(strings.Join(gconv.Strings(vas), "#!#"))
		}

		rs1, _ := db.Model(tbl).OrderDesc(cols[0]).Limit(20).All()
		lstData = ListResult(db, tbl, cols, rs1, msg, w)
		lstData.OnSelected = func(id widget.ListItemID) {
			// selectId = id
			msg.SetText(gconv.String(rs1[id].GMap().Get(cols[0])))
		}
		// 重置数据表格
		CtnData.Objects[0] = lstData
		CtnHeader.Objects[0] = widgets.Header(cols, 2)
		CtnData.Refresh()

		setddl(db, tbl)
	}))
	btnAddCol := widget.NewButton("AddCol", func() {
		w := fyne.CurrentApp().NewWindow("Add column")
		w.Resize(fyne.NewSize(500, 500))
		colName := widget.NewEntry()
		colType := widget.NewSelect(util.SqliteDataType, nil)
		btnOk := widget.NewButton("Ok", func() {
			sql := "ALTER TABLE " + tbl + " ADD " + colName.Text + " " + colType.Selected
			_, err := db.Exec(db.GetCtx(), sql)
			if err != nil {
				msg.SetText(err.Error())
				return
			}
			msg.SetText("add column success")

			nd.AddNewChild(typ, colName.Text)

			lst.Select(len(cols))
			bdcols.Set(len(cols) + 1)
		})
		cc := container.NewVBox(colName, colType, btnOk)
		w.SetContent(cc)
		w.Show()
	})
	btnDelete := widget.NewButton("DeleteCol", func() {
		dialog.ShowConfirm("Delete Column", "Delete column "+colNamesel,
			func(b bool) {
				if b {
					sql := "ALTER TABLE " + tbl + " DROP " + colNamesel
					_, err := db.Exec(db.GetCtx(), sql)
					if err != nil {
						msg.SetText(err.Error())
						return
					}
					msg.SetText("drop column " + colNamesel + " success")

					nd.DeleteChildByName(colNamesel, true)

					lst.Select(selectedID - 1)
					bdcols.Set(len(cols) - 1)
				}
			}, w)
	})
	top := container.NewHBox(btnAddCol, btnDelete)
	left := container.NewBorder(top, nil, nil, nil,
		container.NewBorder(head, lbl, nil, nil, ctnlst))
	cc := container.NewHSplit(left, right)
	cc.Offset = 0.7
	return cc
}

// 字段数据绑定列表
var bdl = binding.NewStringList()

func FieldList(numfd int) *widget.List {
	ll := widget.NewListWithData(bdl, func() fyne.CanvasObject {
		hb := container.NewGridWithColumns(numfd)
		for i := 0; i < numfd; i++ {
			hb.Add(widget.NewLabel("field"))
		}
		return hb
	}, func(di binding.DataItem, co fyne.CanvasObject) {
		hb := co.(*fyne.Container)
		strib := di.(binding.String)
		stri, _ := strib.Get()
		sl := strings.Split(stri, "#!#")
		for i := 0; i < numfd; i++ {
			lbli := hb.Objects[i].(*widget.Label)
			lbli.SetText(sl[i])
		}
	})
	return ll
}

// 使用反射获取结构体gdb.TableField的所有字段及其值
func Field2(db gdb.DB, tbl string) fyne.CanvasObject {
	// fds, _ := db.TableFields(newDb.GetCtx(), tbl)
	// 表的列名数组
	// fds, cols := SqliteTblColsGF(db, tbl)
	fds, cols := TableFields2(db, tbl)
	// 表的列结构体类型
	ty0 := reflect.TypeOf(*fds[cols[0]])
	// 表的列结构体字段数量
	numfd := ty0.NumField()
	// 表头,表的列结构体字段
	head := container.NewGridWithColumns(numfd)
	for i := 0; i < numfd; i++ {
		head.Add(widget.NewLabel(ty0.Field(i).Name))
	}

	lst := widget.NewList(func() int {
		return len(cols)
	}, func() fyne.CanvasObject {
		hb := container.NewGridWithColumns(numfd)
		for i := 0; i < numfd; i++ {
			hb.Add(widget.NewLabel("field"))
		}
		return hb
	}, func(lii widget.ListItemID, co fyne.CanvasObject) {
		hb := co.(*fyne.Container)
		vai := reflect.ValueOf(*fds[cols[lii]])
		for i := 0; i < numfd; i++ {
			lbli := hb.Objects[i].(*widget.Label)
			lbli.SetText(gconv.String(vai.Field(i).Interface()))
		}
	})
	lbl := widget.NewLabel("")
	lst.OnSelected = func(id widget.ListItemID) {
		lbl.SetText(gconv.String(fds[cols[id]]))
	}
	return container.NewBorder(head, lbl, nil, nil, lst)
}

// 获取结构体gdb.TableField的所有字段及其值
func field1(db gdb.DB, tbl string) fyne.CanvasObject {
	// fds, _ := db.TableFields(newDb.GetCtx(), tbl)
	// cols := GetFields(db, tbl)
	// fds, cols := SqliteTblColsGF(db, tbl)
	fds, cols := TableFields2(db, tbl)
	head := container.NewGridWithColumns(8)
	head.Add(widget.NewLabel("Name"))
	head.Add(widget.NewLabel("Index"))
	head.Add(widget.NewLabel("Type"))
	head.Add(widget.NewLabel("Null"))
	head.Add(widget.NewLabel("Key"))
	head.Add(widget.NewLabel("Default"))
	head.Add(widget.NewLabel("Extra"))
	head.Add(widget.NewLabel("Comment"))
	lst := widget.NewList(func() int {
		return len(cols)
	}, func() fyne.CanvasObject {
		hb := container.NewGridWithColumns(8)
		for i := 0; i < 8; i++ {
			hb.Add(widget.NewLabel("field"))
		}
		return hb
	}, func(lii widget.ListItemID, co fyne.CanvasObject) {
		hb := co.(*fyne.Container)
		lbl0 := hb.Objects[0].(*widget.Label)
		lbl0.SetText(fds[cols[lii]].Name)
		lbl1 := hb.Objects[1].(*widget.Label)
		lbl1.SetText(strconv.Itoa(fds[cols[lii]].Index))
		lbl2 := hb.Objects[2].(*widget.Label)
		lbl2.SetText(fds[cols[lii]].Type)
		lbl3 := hb.Objects[3].(*widget.Label)
		lbl3.SetText(gconv.String(fds[cols[lii]].Null))
		lbl4 := hb.Objects[4].(*widget.Label)
		lbl4.SetText(fds[cols[lii]].Key)
		lbl5 := hb.Objects[5].(*widget.Label)
		lbl5.SetText(gconv.String(fds[cols[lii]].Default))
		lbl6 := hb.Objects[6].(*widget.Label)
		lbl6.SetText(fds[cols[lii]].Extra)
		lbl7 := hb.Objects[7].(*widget.Label)
		lbl7.SetText(fds[cols[lii]].Comment)
	})
	lbl := widget.NewLabel("")
	lst.OnSelected = func(id widget.ListItemID) {
		lbl.SetText(gconv.String(fds[cols[id]]))
	}
	return container.NewBorder(head, lbl, nil, nil, lst)
}
